package mbp.agents;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;

import mbp.base.MessageType;
import mbp.core.Resource;
import mbp.core.ResourceValidation;
import mbp.exceptions.ParseExpressionErrorException;
import mbp.gui.frames.ResourceStorageGui;
import mbp.message.Message;
import mbp.message.MessageXml;
import mbp.message.ObjectBuilder;
import mbp.message.extra;
import mbp.message.resource;
import jade.core.AID;
import jade.core.Agent;
import jade.core.behaviours.TickerBehaviour;
import jade.lang.acl.ACLMessage;

public class MbpStorageAgent extends AMbpAgentMap
{
	//public List<Resource> resourceList;
	private ResourceStorageGui agentGui;
	
	//private List<String> storageObservers = new ArrayList<String>();
	
	private Logger logger = Logger.getLogger(this.getClass());
	
	@Override
	protected void setup()
	{
		super.setup();
		
		//storageObservers.add("srv1");
		
		ResourceChecker resourceChecker = new ResourceChecker(this, 1000);
		addBehaviour(resourceChecker);
		
		agentGui = new ResourceStorageGui(this);
		agentGui.setVisible(true);
		
		//System.out.println("ResourceStorage " + getAID().getName() + " is ready.");
		logger.info("Agent " + getAID().getName() + " is ready.");
	}
	
	/**
	 * Implementuje dodatkowe czynnosci
	 */
	public void processMessage(mbp.message.Message iMsg, String senderName)
	{
		MessageType messageType = iMsg.getMessageType();
		switch(messageType)
		{
		case RESOURCE:
			updateGui();
		case RESOURCEDEL:
			updateGui();
			break;
		}
	}
	
	private List<Resource> getListType(List<Resource> resourceList, String type)
	{
		List<Resource> returnList = new ArrayList<Resource>();
		
		for(int i = 0; i<resourceList.size(); i++)
		{
			if(type.compareTo(resourceList.get(i).getType().getResourceTypeName())==0)
			{
				returnList.add(resourceList.get(i));
			}
		}
		
		return returnList;
	}
	
	private List<Resource> getOwnerType(List<Resource> resourceList, String owner)
	{
		List<Resource> returnList = new ArrayList<Resource>();
		
		for(int i = 0; i<resourceList.size(); i++)
		{
			if(owner.compareTo(resourceList.get(i).getOwner())==0)
			{
				returnList.add(resourceList.get(i));
			}
		}
		
		return returnList;
	}
	
	/**
	 * Nadpisuje metode zadanie przeslania listy zasobow. Implementuje dodatkowe warunki - type, owner
	 */
	public void onResourceLGet(mbp.message.Message iMsg, String senderName)
	{
		List<extra> ex = iMsg.getContentXml().extras;
		
		// Dzialanie standardowe - przeslanie tylko listy
		if(ex.size() == 0)
		{
			super.onResourceLGet(iMsg, senderName);
			return;
		}
		
		// Odnalezienie i przeslanie pelnych zasobow
		List<String> rcToSend = new ArrayList<String>();
		
		Iterator<String> it = resourceList.keySet().iterator();
		while(it.hasNext())
		{
			String keyUuid = it.next();
			
			if(ex.get(0).name.compareTo("owner")==0)
			{
				if(ex.get(0).value.compareTo(resourceList.get(keyUuid).getOwner())==0)
				{
					rcToSend.add(new String(keyUuid));
				}
				continue;
			}
			
			if(ex.get(0).name.compareTo("type")==0)
			{
				if(ex.get(0).value.compareTo(resourceList.get(keyUuid).getType().getResourceTypeName())==0)
				{
					rcToSend.add(new String(keyUuid));
				}
			}
		}
		
		ObjectBuilder obb = new ObjectBuilder();
		Message message = new Message(MessageType.RESOURCEL, getLocalName(), senderName);
		for(int i = 0; i<rcToSend.size(); i++)
		{
			resource rci = obb.getResourceInfo(resourceList.remove(rcToSend.get(i)));
			message.getContentXml().resources.add(rci);
		}
		ACLMessage msgReply = message.GetACLMessage();
		SenderLogger.send(this, msgReply);
		
		updateGui();
	}
	
	/**
	 * Obsluga wiadomosci RESOURCEGET - przeslanie jednego zasobu. Jezeli w wyniku dodatkowych warukow
	 * istnieje wiecej zasobow spelniajacych dany warunek, zostanie zwrocony pierwszy pasujacy zasob.
	 */
	public void onResourceGet(mbp.message.Message iMsg, String senderName)
	{
		//Resource rc = null;
		List<extra> exList = iMsg.getContentXml().extras;
		
		int cndCount = exList.size();
		boolean isInStorage = false;
		
		if(cndCount == 0)
		{
			super.onResourceGet(iMsg, senderName);
			return;
		}
		
		// Stworzenie kopii identyfikatorow zasobow bedacych w magazynie z watroscia wystepowania w warunku
		// Liczone sa warunki i jezeli zasob spelnia wszystkie jest przeznaczony do wyslania
		Map<String, Integer> uuidSet = new HashMap<String, Integer>();
		Iterator<String> itUuid = resourceList.keySet().iterator();
		while(itUuid.hasNext())
		{
			String key = new String(itUuid.next());
			uuidSet.put(key, 0);
		}
		
		for(int i = 0; i<cndCount; i++)
		{
			String exCnd = exList.get(i).name;
			
			// 
			if(exCnd.compareTo("owner")==0)
			{
				String owner = exList.get(i).value;
				Iterator<String> it = resourceList.keySet().iterator();
				while(it.hasNext())
				{
					String key = it.next();
					if(resourceList.get(key).getOwner().compareTo(owner)==0)
					{
						Integer c = uuidSet.get(key);
						c = c + 1;
						uuidSet.put(key, c);
					}
				}
				continue;
			}
			
			// 
			if(exCnd.compareTo("type")==0)
			{
				String type = exList.get(i).value;
				Iterator<String> it = resourceList.keySet().iterator();
				while(it.hasNext())
				{
					String key = it.next();
					if(resourceList.get(key).getType().getResourceTypeName().compareTo(type)==0)
					{
						Integer c = uuidSet.get(key);
						c = c + 1;
						uuidSet.put(key, c);
					}
				}
				continue;
			}
			
			if(exCnd.compareTo("validation")==0)
			{
				ResourceValidation rcv = iMsg.getResourceValidation().get(0);
				rcv.setExactQt(true);
				Iterator<String> it = resourceList.keySet().iterator();
				while(it.hasNext())
				{
					String key = it.next();
					String type = rcv.getType().getResourceTypeName();
					Resource rc = resourceList.get(key);
					if(type.compareTo(rc.getType().getResourceTypeName())==0)
					{
						try {
							if(rcv.validateCondition(rc))
							{
								Integer c = uuidSet.get(key);
								c = c + 1;
								uuidSet.put(key, c);
							}
						} catch (ParseExpressionErrorException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
				}
			}
		}//for(int i = 0; i<exList.size(); i++)
		
		
		Iterator<String> itCnd = uuidSet.keySet().iterator();
		while(itCnd.hasNext())
		{
			String uuid = itCnd.next();
			int counter = uuidSet.get(uuid);
			if(counter == cndCount)
			{
				Resource rcToSend = resourceList.get( uuid );
				Message message = new Message(MessageType.RESOURCE, getLocalName(), senderName);
				message.setResource(rcToSend);
				SenderLogger.send(this, message.GetACLMessage());
				deleteResource(uuid);
				isInStorage = true;
				break;
			}
		}
		
		if(isInStorage == false)
		{
			Message message = new Message(MessageType.ERROR, getLocalName(), senderName);
			SenderLogger.send(this, message.GetACLMessage());
		}
		

		
//		//Pierwszy spelniajacy inny warunek
//		
//		if((iMsg.getContentXml().validations.size() == 1) && (iMsg.getContentXml().resources.size() == 1))
//		{
//			ResourceValidation rcv = iMsg.getResourceValidation().get(0);
//			Iterator<String> it = resourceList.keySet().iterator();
//			String toDel = "";
//			while(it.hasNext())
//			{
//				String key = it.next();
//				String type = rcv.getType().getResourceTypeName();
//				String owner = iMsg.getContentXml().resources.get(0).owner;
//				rc = resourceList.get(key);
//				
//				if(owner.compareTo(rc.getOwner())!=0)
//				{
//					continue;
//				}
//				
//				if(type.compareTo(rc.getType().getResourceTypeName())==0)
//				{
//					try {
//						if(rcv.validateCondition(rc))
//						{
//							Message message = new Message(MessageType.RESOURCE, getLocalName(), senderName);
//							message.setResource(rc);
//							SenderLogger.send(this, message.GetACLMessage());
//							toDel = new String(key);
//							break;
//						}
//					} catch (ParseExpressionErrorException e) {
//						e.printStackTrace();
//					}
//				}
//			}
//			
//			if(toDel.compareTo("")!=0)
//			{
//				deleteResource(toDel);
//			}
//			
//			
//		}
//		
//		if((iMsg.getContentXml().validations.size() == 0) && (iMsg.getContentXml().resources.size() == 1))
//		{
//			String uuid = iMsg.getContentXml().resources.get(0).resourceid;
//			if(resourceList.containsKey(uuid))
//			{
//				rc = resourceList.get(uuid);
//				Message message = new Message(MessageType.RESOURCE, getLocalName(), senderName);
//				message.setResource(rc);
//				SenderLogger.send(this, message.GetACLMessage());
//				
//				deleteResource(uuid);
//			}
//		}
	}
	
	/**
	 * Zwraca referencje do zasobu z magazynu o podanym uuid
	 * @param uuid
	 * @return
	 */
	public Resource getResource(String uuid)
	{
		return resourceList.get(uuid);
	}
	
	/**
	 * Kasuje zasob w magazynie o podanym uuid
	 * @param uuid
	 */
	public void deleteResource(String uuid)
	{
		resourceList.remove(uuid);
		//GuiUpdater ga = new GuiUpdater();
		//ga.start();
		updateGui();
	}
	
	/**
	 * Sprawdzenie zasobu pod katem waznosci. Zasoby ktorych termin waznosci uplynal sa usuwane.
	 * @author Wojciech Wilanski
	 *
	 */
	public class ResourceChecker extends TickerBehaviour
	{

		public ResourceChecker(Agent a, long period) {
			super(a, period);
		}

		@Override
		protected void onTick() 
		{
			Iterator<String> it = resourceList.keySet().iterator();
			ArrayList<String> toRemove = new ArrayList<String>();
			Boolean removed = false;
			
			//Wyszukanie zasobow przeterminowanych
			while(it.hasNext())
			{
				String keyUuid = it.next();
				
				Resource rc = resourceList.get(keyUuid);
				
				if(!rc.isValid())
				{
					toRemove.add(keyUuid);
					removed = true;
				}
			}
			
			//usuniecie zasobow przeterminowanych
			for(int i = 0; i<toRemove.size(); i++)
			{
				resourceList.remove(toRemove.get(i));
			}
			
			//Odswierzenie listy na gui
			if(removed)
			{
				if(agentGui != null)
				{
					updateGui();
				}
			}
		}
	}
	
	public void updateGui()
	{
		//List<Resource> rcList = new ArrayList<Resource>(resourceList.values());
		List<resource> rciList = new ArrayList<resource>();
		Iterator<String> it = resourceList.keySet().iterator();
		while(it.hasNext())
		{
			resource rci = new resource();
			rci.resourceid = new String(it.next());
			rci.type = new String(resourceList.get(rci.resourceid).getType().getResourceTypeName());
			rci.owner = new String(resourceList.get(rci.resourceid).getOwner());
			
			rciList.add(rci);
			
		}
		agentGui.reloadResources(rciList);
	}
	

//	public void addObserver(String storageObserver) {
//		storageObservers.add(storageObserver);
//		
//	}
//
//	public void deleteObserver(String storageObserver) {
//		storageObservers.remove(storageObserver);
//		
//	}

//	public void storageChanged() {
//		
//		//if(storageObservers.size() == 0)return;
//		
//		Iterator<String> it = resourceList.keySet().iterator();
//		List<resource> rciList = new ArrayList<resource>();
//		while(it.hasNext())
//		{
//			String keyUuid = it.next();
//			resource rc = new resource();
//			rc.type = resourceList.get(keyUuid).getType().getResourceTypeName();
//			rc.owner = resourceList.get(keyUuid).getOwner();
//			rc.resourceid = resourceList.get(keyUuid).getUUID();
//			rciList.add(rc);
//		}
//		
//		MessageXml mxml = new MessageXml();
//		for(int i = 0; i<rciList.size(); i++)
//		{
//			mxml.resources.add(rciList.get(i));
//		}
//		
//		Message message = new Message(MessageType.RESOURCEL, getLocalName(), storageObservers.get(0));
//		message.setContentXml(mxml);
//		ACLMessage msgReply = message.GetACLMessage();
//		
//		for(int i = 1; i<storageObservers.size(); i++)
//		{
//			msgReply.addReceiver(new AID(storageObservers.get(i), AID.ISLOCALNAME));
//		}
//		
//		SenderLogger.send(this, msgReply);
//	}
}

